package com.owner.demo.springbootdemo.CircuitBreaker;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 时间间隔计数器
 * @author lcb52
 * @date 2020-9-2
 */
@Slf4j
public class CircuitBreaker {


    private CircuitBreakerConfig config;

    private volatile CircuitBreakerStateEnum state = CircuitBreakerStateEnum.CLOSED;

    //最近进入open状态的时间
    private volatile long lastOpenedTime;

    /**
     * 时间间隔计数器
     */
    private TimeIntervalCounter counter ;

    //half-open状态的连续成功次数,失败立即清零
    private AtomicInteger consecutiveSuccCount = new AtomicInteger(0);

    //构造器
    public CircuitBreaker(CircuitBreakerConfig config) {
        this.config = config;
        counter = new TimeIntervalCounter(config.getFailCountWindowInMs(), config.getFailThreshold());
    }

    //状态判断
    public boolean isOpen(){
        return CircuitBreakerStateEnum.OPEN == state;
    }

    public boolean isClosed(){
        return CircuitBreakerStateEnum.CLOSED == state;
    }

    //状态操作

    /**
     * closed->open | halfopen -> open
     */
    public void open(){
        state = CircuitBreakerStateEnum.OPEN;
    }

    /**
     * halfopen -> close
     */
    public void close(){
        counter.reset();
        state = CircuitBreakerStateEnum.CLOSED;
    }

    //阈值判断
    /**
     * 是否应该从close转到open
     * @return
     */
    public boolean isClose2Open(){
        return counter.ltThreshold();
    }

    /**
     * 是否应该从close转到open
     * @return
     */
    public boolean isOpen2Close(){
        return isOpen() && (lastOpenedTime + config.getOpenTimeoutInMs()) < System.currentTimeMillis();
    }

    //getter
    public void incrFailCount() {
        lastOpenedTime = System.currentTimeMillis();
        int count = counter.incrAndGet();
    }

    public AtomicInteger getConsecutiveSuccCount() {
        return consecutiveSuccCount;
    }

    public CircuitBreakerStateEnum getState() {
        return state;
    }

}
